// 环形队列（使用取模实现）


// 队列核心逻辑
class RingQueue {
    constructor(arrmMaxSize) {
        let maxSize = arrmMaxSize; // 表示数组最大容量
        let arr = []; // 队列数组，模拟队列
        let front = 0; // 队列头,指向队列头,从0开始
        let rear = 0; // 队列尾，指向队列尾

        // 判断队列是否满
        this.isFull = () => {
            return (rear + 1) % maxSize === front;
        }

        // 判断队列是否为空
        this.isEmpty = () => {
            return rear === front;
        }

        // 添加数据到队列
        this.addQueue = (n) => {
            // 已满
            if (this.isFull()) {
                throw "队列已满";
                // 添加队列
            } else {
                arr[rear] = n; // 因为默认是0，添加一个就是给该位置赋值
                rear = (rear + 1) % maxSize; // 添加一个以后，rear要向后移动一位，应为是环形，所有要 % 上长度
                                             // 把 rear 指到前面来，就可以一直添加队列
            }
        }

        // 取出队列
        this.getQueue = () => {
            // 为空
            if (this.isEmpty()) {
                throw "队列为空不能取数据";
                // 非空
            } else {
                // 这里需要分析出 front 是指向队列的第一个元素
                // 1.先把 front 对应的值保留到一个临时变量
                // 2.将 front 后移
                // 3.将临时保存的变量返回
                let temporary = arr[front]
                // front++;// 不能这样后移动，要考虑取模
                front = (front + 1) % maxSize; // 这里有点绕 
                return temporary;
            }
        }

        // 显示队列的所有数据
        this.showQueue = () => {
            // 为空
            if (this.isEmpty()) {
                console.log("队列为空");
            } else {
                // for (let i = 0; i < arr.length; i++) {
                //     console.log(`arr[${i}]=${arr[i]}`);
                // }
                // 思路：从 front 开始遍历，遍历多少个元素个数
                // (0): 当前队列有效的个数
                for (let i = front; i < front + (this.size()); i++) {
                    // 这个地方也比较绕
                    console.log(`arr[${i % maxSize}]=${arr[i % maxSize]}`);
                }
            }
        }


        // 获取当前队列有效个数
        this.size = () => {
            // 譬如在默认基础上添加了一个有效队列，front和rear就会变成一下的值
            // rear = 1 // 添加了一个队列， rear 就要向后移一为
            // front = 0
            // maxSize = 2
            // 有效个数 (1 + 2 - 0) % 2 = 1
            return (rear + maxSize - front) % maxSize;
        }

        // 显示队列的头数据
        this.headQueue = () => {
            // 为空
            if (this.isEmpty()) {
                throw "队列为空没有数据";
            } else {
                return arr[front];// front本身就指向队列的第一个元素
            }
        }
    }
}

let ringQueue = new RingQueue(4);




// 操作队列逻辑
const readline = require('readline')

let str = '\r\n请输入你的操作\r\n';
str += 's(show):显示队列\r\n';
str += 'e(exit):退出程序\r\n';
str += 'a(add):添加数据到队列\r\n';
str += 'g(get):从队列里取出数据\r\n';
str += 'h(head):查看队列头数据\r\n\r\n';

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: str
})
rl.prompt();
rl.on('line', async (line) => {
    switch (line.trim()) {
        case 's':
            ringQueue.showQueue();
            break;
        case 'a':
            try {
                ringQueue.addQueue(new Date() * 1);
            } catch (e) {
                console.log(e);
            }
            break;
        case 'g':
            try {
                console.log(ringQueue.getQueue());
            } catch (e) {
                console.log(e);
            }
            break;
        case 'h':
            try {
                console.log(ringQueue.headQueue());
            } catch (e) {
                console.log(e);
            }
            break;
        case 'e':
            rl.close();
            process.exit(0);
            break;
        default:
            console.log(`你输入的是：'${line.trim()}'`);
            break;
    }
    rl.prompt();
}).on('close', () => {
    console.log('再见!');
    process.exit(0);
})


// 总结： 到此队列基本实现完成,不过存在问题，当队列取完时，在添加队列就添加不上了